<template>
   <!-- 数字动画 -->
   <span style="font-size: 28px">{{ displayValue }}</span>
</template>

<script>
   export default {
      name: "CountTo",
      props: {
         startVal: {
            type: Number,
            default: 0,
         },
         endVal: {
            type: Number,
            required: true,
         },
         duration: {
            type: Number,
            default: 2000,
         },
         decimal: {
            type: Number,
            default: 0,
         },
         separator: {
            type: String,
            default: "",
         },
         prefix: {
            type: String,
            default: "",
         },
         suffix: {
            type: String,
            default: "",
         },
         autoplay: {
            type: Boolean,
            default: true,
         },
      },
      data() {
         return {
            displayValue: this.formatValue(this.startVal),
            localStartVal: this.startVal,
            printVal: null,
            animationFrame: null,
            start: null,
            remaining: null,
            localDuration: this.duration,
            isAnimating: false,
         };
      },
      computed: {
         countDown() {
            return this.startVal > this.endVal;
         },
      },
      watch: {
         autoplay: {
            handler(newValue) {
               if (newValue) {
                  this.startFunc();
               }
            },
            immediate: true,
         },
         startVal() {
            this.localStartVal = this.startVal;
            this.displayValue = this.formatValue(this.startVal);
         },
         endVal() {
            this.isAnimating = false;
            this.startFunc();
         },
      },
      mounted() {
         if (this.autoplay) {
            this.startFunc();
         }
      },
      beforeUnmount() {
         this.reset();
      },
      methods: {
         startFunc() {
            this.isAnimating = true;
            this.reset();
            this.localStartVal = this.startVal;

            if (this.startVal === this.endVal) {
               this.displayValue = this.formatValue(this.endVal);
               return;
            }

            this.printVal = this.startVal;
            this.remaining = this.localDuration;

            // 开始动画
            this.animationId = requestAnimationFrame(this.animate);
         },
         animate(timestamp) {
            if (!this.start) {
               this.start = timestamp;
            }

            const progress = timestamp - this.start;
            this.remaining = this.localDuration - progress;

            // 进度计算
            if (this.countDown) {
               this.printVal = this.localStartVal - (this.localStartVal - this.endVal) * (progress / this.localDuration);
            } else {
               this.printVal = this.localStartVal + (this.endVal - this.localStartVal) * (progress / this.localDuration);
            }

            // 确保不超过目标值
            if (this.countDown) {
               this.printVal = this.printVal < this.endVal ? this.endVal : this.printVal;
            } else {
               this.printVal = this.printVal > this.endVal ? this.endVal : this.printVal;
            }

            // 更新显示值
            this.displayValue = this.formatValue(this.printVal);

            // 动画完成或继续
            if (progress < this.localDuration) {
               this.animationId = requestAnimationFrame(this.animate);
            } else {
               this.isAnimating = false;
               this.displayValue = this.formatValue(this.endVal);
            }
         },
         reset() {
            if (this.animationId) {
               cancelAnimationFrame(this.animationId);
               this.animationId = null;
            }
            this.start = null;
         },
         formatValue(val) {
            // 格式化数字
            let formattedValue = parseFloat(val).toFixed(this.decimal);

            // 处理千分位分隔符
            // if (this.separator) {
            //   const parts = formattedValue.toString().split('.');
            //   parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, this.separator);
            //   formattedValue = parts.join('.');
            // }

            // 添加前缀和后缀
            return this.prefix + formattedValue + this.suffix;
         },
      },
   };
</script>

<style scoped>
   /* 可以添加样式 */
</style>
